package com.xli.mis.codeitems.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheManager;
import com.alicp.jetcache.anno.CacheConsts;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.template.QuickConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xli.mis.codeitems.entity.CodeItems;
import com.xli.mis.codeitems.entity.CodeItemsCache;
import com.xli.mis.codeitems.mapper.CodeItemsMapper;
import com.xli.mis.codeitems.mapper.ICodeItemsCacheMapper;
import com.xli.mis.codeitems.service.ICodeItemsService;
import com.xli.mis.codemain.service.ICodeMainService;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Validated
@Service
public class CodeItemsServiceImpl extends ServiceImpl<CodeItemsMapper, CodeItems> implements ICodeItemsService {

    private final Lock lock = new ReentrantLock();

    @Autowired
    CacheManager cacheManager;

    Cache<Long, List<CodeItemsCache>> codeItemCache;

    @PostConstruct
    public void init() {
        lock.lock();
        try {
            QuickConfig qc = QuickConfig.newBuilder("code_items:list:")
                    .expire(Duration.ofSeconds(CacheConsts.DEFAULT_EXPIRE))
                    .cacheType(CacheType.BOTH)
                    .syncLocal(true)
                    .build();
            codeItemCache = cacheManager.getOrCreateCache(qc);

            List<CodeItems> codeItemsList = this.findList(new QueryWrapper<>());
            List<CodeItemsCache> codeItemsCacheList = ICodeItemsCacheMapper.INSTANCE.toCacheList(codeItemsList);

            Map<Long, List<CodeItemsCache>> groupList = codeItemsCacheList.stream()
                    .collect(Collectors.groupingBy(CodeItemsCache::getCode_id));
            groupList.forEach((codeId, cacheList) -> {
                cacheList.sort(Comparator.comparing(CodeItemsCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                codeItemCache.put(codeId, cacheList);
            });
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean insert(CodeItems codeItems) {
        lock.lock();
        try {
            boolean result = this.save(codeItems);
            if (result) {
                List<CodeItemsCache> codeItemsCacheList = codeItemCache.get(codeItems.getCode_id());
                if (codeItemsCacheList == null) {
                    codeItemsCacheList = new ArrayList<>();
                }
                codeItemsCacheList.add(ICodeItemsCacheMapper.INSTANCE.toCacheEntity(codeItems));
                codeItemsCacheList.sort(Comparator.comparing(CodeItemsCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                codeItemCache.put(codeItems.getCode_id(), codeItemsCacheList);
            }
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean delete(Long id) {
        lock.lock();
        try {
            CodeItems codeItems = this.find(id);
            if (codeItems != null) {
                boolean result = this.removeById(id);
                if (result) {
                    List<CodeItemsCache> codeItemsCacheList = codeItemCache.get(codeItems.getCode_id());
                    if (codeItemsCacheList == null) {
                        codeItemsCacheList = new ArrayList<>();
                    }
                    codeItemsCacheList.removeIf(cache -> cache.getId().equals(codeItems.getId()));
                    codeItemCache.put(codeItems.getCode_id(), codeItemsCacheList);
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean deleteByCodeId(Long codeId) {
        lock.lock();
        try {
            QueryWrapper<CodeItems> qw = new QueryWrapper<>();
            qw.lambda().eq(CodeItems::getCode_id, codeId);
            boolean result = this.remove(qw);
            if (result) {
                codeItemCache.remove(codeId);
            }
            return result;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean update(CodeItems codeItems) {
        lock.lock();
        try {
            CodeItems items = this.find(codeItems.getId());
            if (items != null) {
                boolean result = this.updateById(codeItems);
                if (result) {
                    List<CodeItemsCache> codeItemsCacheList = codeItemCache.get(codeItems.getCode_id());
                    if (codeItemsCacheList == null) {
                        codeItemsCacheList = new ArrayList<>();
                    }
                    codeItemsCacheList.removeIf(cache -> cache.getId().equals(items.getId()));
                    codeItemsCacheList.add(ICodeItemsCacheMapper.INSTANCE.toCacheEntity(codeItems));
                    codeItemCache.put(codeItems.getCode_id(), codeItemsCacheList);
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public CodeItems find(Long id) {
        return this.getById(id);
    }

    @Override
    public List<CodeItems> findList(QueryWrapper<CodeItems> qw) {
        return this.list(qw);
    }

    @Override
    public Page<CodeItems> findList(QueryWrapper<CodeItems> qw, long current, long size) {
        return this.page(new Page<>(current, size), qw);
    }

    @Override
    public long findCount(QueryWrapper<CodeItems> qw) {
        return this.count(qw);
    }

    @Override
    public List<CodeItems> findItemListByCodeId(Long codeId) {
        List<CodeItemsCache> cacheList = codeItemCache.get(codeId);
        if (cacheList == null) {
            cacheList = new ArrayList<>();
        }
        return ICodeItemsCacheMapper.INSTANCE.toEntityList(cacheList);
    }

    @Override
    public List<CodeItems> findItemListByCodeName(String codeName) {
        ICodeMainService iCodeMainService = SpringUtil.getBean(ICodeMainService.class);
        Long codeId = iCodeMainService.getCodeIdByName(codeName);
        if (codeId != null) {
            return findItemListByCodeId(codeId);
        }
        return new ArrayList<>();
    }

    @Override
    public boolean isExists(Long codeId, String value) {
        List<CodeItems> codeItemsList = this.findItemListByCodeId(codeId);
        for (CodeItems codeItems : codeItemsList) {
            if (codeItems.getItem_value().equals(value)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String findItemTextByValue(String codeName, String itemValue) {
        List<CodeItems> codeItemsList = this.findItemListByCodeName(codeName);
        for (CodeItems codeItems : codeItemsList) {
            if (codeItems.getItem_value().equals(itemValue)) {
                return codeItems.getItem_text();
            }
        }
        return "";
    }
}
